package com.ZeroCarbon.service.impl;

import com.ZeroCarbon.domain.dto.GoodsDetailDTO;
import com.ZeroCarbon.domain.dto.GoodsPreviewDTO;
import com.ZeroCarbon.domain.dto.GoodsReceiverDTO;
import com.ZeroCarbon.domain.dto.IdentityDetailDTO;
import com.ZeroCarbon.domain.po.Good;
import com.ZeroCarbon.domain.po.Identity;
import com.ZeroCarbon.entity.PageObject;
import com.ZeroCarbon.exception.BusinessLogicException;
import com.ZeroCarbon.mapper.GoodsMapper;
import com.ZeroCarbon.service.IGoodsService;
import com.ZeroCarbon.service.IIdentityService;
import com.ZeroCarbon.utils.UserHolder;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

import static com.ZeroCarbon.exception.BusinessLogicException.ERROR_EXCEPTION;
import static com.ZeroCarbon.prefix.MySqlKey.GOOD_PREFIX;
import static com.ZeroCarbon.prefix.MySqlKey.generateId;

@Slf4j
@Service
@RequiredArgsConstructor
public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Good> implements IGoodsService {

    private final IIdentityService identityService;

    /**
     * 增加商品
     */
    @Override
    public void addGood(GoodsReceiverDTO goodsReceiverDTO) throws BusinessLogicException {
        //商品价格
        double price = goodsReceiverDTO.getPrice();
        //商品所需积分
        int integral = goodsReceiverDTO.getIntegral();
        //设置商品设置限制
        if (price < 0 || price > 10000000) {
            throw new BusinessLogicException("商品价格设置范围为0~10000000元");
        } else if (integral < 0 || integral > 10000) {
            throw new BusinessLogicException("商品积分设置范围为0~10000元");
        }
        //生成id
        String id = generateId(GOOD_PREFIX);
        //用户id
        String userId = UserHolder.getUser();
        //转化对象
        Good good = goodsReceiverDTO.toGood();
        //设置id和用户id
        good.setId(id)
                .setUserId(userId);
        try {
            //没有保存成功就抛异常
            if (!save(good)) {
                throw new BusinessLogicException();
            }
        } catch (Exception e) {
            log.error(e.toString());
            throw new BusinessLogicException(ERROR_EXCEPTION);
        }
    }


    /**
     * 获取当前用户商品列表/随机获取用户列表
     *
     * @param page      页码
     * @param size      页长
     * @param isSave    是否获取保存的商品列表
     * @param randomGet 是否随机获取（是则随机获取，否则获取当前用户商品列表）
     */
    @Override
    public PageObject getGoodsList(int page, int size, boolean isSave, boolean randomGet) throws BusinessLogicException {
        //分页对象
        Page<Good> goodsPage = new Page<>(1, 9999);
        //如果传入列表
        //条件构造器
        LambdaQueryWrapper<Good> goodWrapper = new LambdaQueryWrapper<>();
        //如果不是随机获取的情况
        if (!randomGet) {
            //获取用户id
            String userId = UserHolder.getUser();
            //如果不是随机获取情况，就是获取当前用户商品列表
            goodWrapper
                    .eq(Good::getUserId, userId)
                    .eq(Good::isSaveCondition, isSave);
        }
        //记录分页结果
        Page<Good> result;
        try {
            //根据构造器和分页对象获取
            result = page(goodsPage, goodWrapper);
        } catch (Exception e) {
            throw new BusinessLogicException(ERROR_EXCEPTION);
        }
        //获取结果
        List<Good> goods = result.getRecords();
        //处理信息
        List<GoodsPreviewDTO> goodsPreviewsDTO = getGoodsPreviewDTOList(goods);
        //返回分页情况
        return new PageObject(goodsPreviewsDTO, page, goodsPage.getTotal(), size, goodsPage.getPages());
    }

    /**
     * 获取当前用户商品详细信息
     */
    @Override
    public GoodsDetailDTO getGoodDetail(String id) throws BusinessLogicException {
        //获取物品条件构造器
        LambdaQueryWrapper<Good> goodWrapper = new LambdaQueryWrapper<Good>()
                .eq(Good::getId, id)
                .eq(Good::isSaveCondition, 0);
        //记录商品信息
        Good good = null;
        try {
            //获取物品
            good = getOne(goodWrapper);
        } catch (Exception e) {
            throw new BusinessLogicException(ERROR_EXCEPTION);
        }
        //获取身份信息
        IdentityDetailDTO identityDetailDTO = identityService.getIdentity(good.getIdentityId());
        //转化对象
        GoodsDetailDTO goodsDetailDTO = good.toGoodsDetailDTO();
        //设置信息并返回
        return goodsDetailDTO
                //设置身份名字
                .setIdentityName(identityDetailDTO.getName())
                //设置商品身份
                .setAvatar(identityDetailDTO.getImage());
    }

    /**
     * 搜索商品
     */
    @Override
    public List<GoodsPreviewDTO> searchGood(String search, int page, int size) throws BusinessLogicException {
        //分页对象
        Page<Good> goodsPage = new Page<>(page, size);
        //搜索构造器
        LambdaQueryWrapper<Good> searchWrapper = new LambdaQueryWrapper<Good>()
                .like(Good::getName, search)
                .or()
                .like(Good::getTagsJson, search)
                .or()
                .like(Good::getDescription, search);
        //记录商品列表
        List<Good> goodsList;
        try {
            //获取分页结果
            Page<Good> result = page(goodsPage, searchWrapper);
            //获取结果列表
            goodsList = result.getRecords();
        } catch (Exception e) {
            throw new BusinessLogicException(ERROR_EXCEPTION);
        }
        //返回数据列表
        return getGoodsPreviewDTOList(goodsList);
    }

    /**
     * Good类型列表转化为GoodsPreviewDTO类型列表
     */
    private List<GoodsPreviewDTO> getGoodsPreviewDTOList(List<Good> goods) {
        return goods.stream()
                .map(good -> {
                    //转化对象
                    GoodsPreviewDTO goodsPreviewDTO = good.toGoodsPreviewDTO();
                    //记录身份信息
                    Identity identity;
                    try {
                        //获取身份信息
                        identity = Db.lambdaQuery(Identity.class)
                                .eq(Identity::getId, good.getIdentityId())
                                .one();
                    } catch (Exception e) {
                        throw new RuntimeException(ERROR_EXCEPTION);
                    }
                    //如果身份信息不为空则设置信息
                    if (identity != null) {
                        goodsPreviewDTO.setIdentity(identity.getName());
                    }
                    //返回设置好的对象
                    return goodsPreviewDTO;
                }).collect(Collectors.toList());
    }
}
